/*
 * JMonthNavigator.java
 *
 * Created on 7-Mar-2010.
 */

package org.calendar;


import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;

import java.awt.Dimension;
import java.awt.Insets;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import java.util.Calendar;
import java.util.Locale;
import java.text.SimpleDateFormat;
import java.text.DateFormatSymbols;

import org.calendar.event.CalendarModelListener;
import org.calendar.event.ModelChangedEvent;



/**
 * This class is a component to navigate between month.
 * It updates the model with the choosen month to display.
 * It listen to the model calendar changes.
 *
 * @see CalendarModelListener
 * @see DefaultCalendarModel
 *
 * @author Julie Duvillier
 */

public class JMonthNavigator
        extends JPanel
        implements CalendarModelListener,
                   ActionListener  {


    /* model */
    private DefaultCalendarModel model;

    /* locale */
    private Locale locale;

     /* Format of Month string */
    private SimpleDateFormat monthFormat;

    /* Calendar to display fields */
    private Calendar calToDisplay;
    private int displayedMonth;
    private int displayedYear;

    /* Components */
    private JLabel monthLabel;
    private JButton monthDecrButton;
    private JButton monthIncrButton;
    private JButton[] navigButtons;
    
    /* Decoration */
    private Font buttonFont;   
    private Color buttonColor;
    private boolean areaFilled;


    /**
     * Creates a new JMonthNavigator
     */
    public JMonthNavigator () {
        this( new DefaultCalendarModel() );
    }

    /**
     * Creates a new JMonthNavigator with a defined model
     * @param model the calendar Model to be used
     */
    public JMonthNavigator ( DefaultCalendarModel model ) {
        this.model = model;
        this.model.addCalendarModelListener(this);
        this.setLayout( new BorderLayout(2, 2) );
        init();
    }

    /**
     * Initialize the fields needed to build the panel components.
     */
    private void init(){
         calToDisplay =(Calendar)model.getCalendarToDisplay().clone();
         locale = model.getLocale();
         monthFormat =  new SimpleDateFormat("MMMM");
         monthFormat.setDateFormatSymbols( new DateFormatSymbols( locale ) );
         initDecorations();
         initComponents();
         updateComponents();
    }

    private void initDecorations(){
        buttonColor = Color.DARK_GRAY;
        buttonFont = new Font("Tahoma",0,9);
        areaFilled = false;
    }

    /**
     * Initialize the basics layouts and components of the navigator
     * panel with the defaults settings.
     */
    private void initComponents(){
        monthLabel = new JLabel();
        monthLabel.setHorizontalAlignment( JLabel.CENTER );
        navigButtons = new JButton[2];

        monthDecrButton = new JButton("◄");
        monthDecrButton.setActionCommand( "DECREASE" );
        monthIncrButton = new JButton("►");
        monthIncrButton.setActionCommand( "INCREASE" );
        navigButtons[0] = monthDecrButton;
        navigButtons[1] = monthIncrButton;

        buttonFont = monthDecrButton.getFont().deriveFont(0, 9);

        for (JButton b  :navigButtons) {
            b.addActionListener(this);
            b.setForeground(buttonColor);
            b.setContentAreaFilled(areaFilled);
            b.setFont( buttonFont );
            b.setMargin(  new Insets(2,2,3,3) );
            b.setPreferredSize( new Dimension(26,20) );
            b.addMouseListener( new RolloverListener() );
        }

        add( monthDecrButton, BorderLayout.WEST );
        add( monthLabel );
        add( monthIncrButton,BorderLayout.EAST );
    }

    /**
     * Update the navigator panel components with the calendar to
     * display.
     */
    private void updateComponents(){
       String month;    // month of the aclendar to display
       String year;     // year of the aclendar to display

       displayedMonth = calToDisplay.get(Calendar.MONTH);
       displayedYear = calToDisplay.get( Calendar.YEAR);

       month = monthFormat.format( calToDisplay.getTime() );
       month = Character.toUpperCase(month.charAt(0))
                         + month.substring(1);

       year = Integer.toString( displayedYear );

       monthLabel.setText( month + " " + year );

    }

    /* Implements CalendarModelListener */
    /**
     * Invoked when an ModelChangedEvent occur.
     * Set the calendar to display with new calendar
     * and update the panel components.
     * @param e event that hold modifications information on the model calendar
     */
    public void calendarModelChanged ( ModelChangedEvent e ) {
        int newMonth;       // new month to display
        int newYear;        // new year to display
        Locale oldLocale;   // oldLocale


        calToDisplay = (Calendar)e.getCalendarToDisplay().clone();
        newMonth = calToDisplay.get( Calendar.MONTH );
        newYear = calToDisplay.get( Calendar.YEAR );
        oldLocale = locale;
        locale = e.getLocale();

         if( ( newMonth != displayedMonth )
                || ( newYear != displayedYear )
                || ( locale != oldLocale ) ){

            monthFormat.setDateFormatSymbols( new DateFormatSymbols( locale ) );
            updateComponents();
         }
    }

    /* Implements Action Listener */
    /**
     * Invoked when an ActionEvent occur
     * Set the model calendar to the calendar choosen by navigation button.
     * @param e event that hold information of the action
     */
    public void actionPerformed(ActionEvent e) {
        String command;     // command
        Calendar temp;      // temporary calendar

        command = e.getActionCommand() ;
        temp = (Calendar)calToDisplay.clone();

        if ( command.equals( "INCREASE" ) ){
             // add  month to the calendar
             temp.add( Calendar.MONTH, 1 );
        } else if ( command.equals( "DECREASE" ) ){
            // substract  month to the calendar
            temp.add( Calendar.MONTH, -1 );  
        }
        // Set the model calendar
        model.setCalendarToDisplay(temp);
    }

    /* Inner class implementing mouse listener on mouse entered and excited*/
    private class RolloverListener extends MouseAdapter {

        /**
         * Invoked when teh mouse enter the button.
         * Sets the contentAreaFilled property of the button
         * to the opposite of the current status.
         * @param e the mouse event
         */
        @Override
        public void mouseEntered(MouseEvent e){
            ( (JButton)e.getSource()).setContentAreaFilled(  ! areaFilled);
        }

        /**
         * Invoked when the mouse leave the button
         * Set the contentAreaFilled property of the button
         * back to  the current status.
         * @param e  the mouse event
         */
        @Override
        public void mouseExited(MouseEvent e){
          ( (JButton)e.getSource()).setContentAreaFilled(  areaFilled);
        }

    }
    /**
     * Gets the foreground color of buttons.
     * @return buttons's foreground <code>color</code>;
     */
    protected Color getButtonForeground(){
       return buttonColor;
    }

    /**
     * Gets the font of  buttons.
     * @return buttons font.
     */
    protected Font getButtonFont(){
        return buttonFont;
    }

    /**
     * Sets the font of buttons.
     * @param font he font to become buttons font
     */
    protected void setButtonFont(Font font){
        buttonFont = font;
         for (JButton b  :navigButtons) {
             b.setFont( buttonFont );
         }
    }

    /**
     * Sets the foreground color buttons.
     * @param color the color to become the buttons foreground color
     */
    protected void setButtonForeground(Color color){
        buttonColor = color;
         for (JButton b  :navigButtons) {
             b.setForeground(buttonColor);
         }
    }

    /**
     * Sets the contentAreaFilled property of day buttons.
     * If <code>true</code> buttons will paint the content area.
     * <p>
     * The default value is  <code>false </code> and become <code>true</code>
     * on mouse over, So the content is filled on mouse over.
     * <p>
     * The selected button contentAreaFilled property take the opposite
     * value, so if the contentAreaFilled property is <code>true</code>
     * the contentAreaFilled property of tehs elected button will be
     * <code>false</code>.
     * <p>
     * Setting the property to <code>true</code> will reverse this.
     * @param b  if true, the content should be filled
     *              and become not  filled on mouse over;
     *           if false the content area is not filled
     *              and become filled on mouse over
     */
    protected void setButtonAreaFilled(boolean b){
        areaFilled = b;
        for (JButton but  :navigButtons) {
             but.setContentAreaFilled(b);
         }
    }



}





